package cn.kk.utils;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.Function;

/**
 * 对象工具类
 * @author liujunkai
 * @date 2022/7/25 15:21
 */
public class ObjectUtil {

    /**
     * 判断该对象是否所有属性为空
     * 返回ture表示所有属性为null，返回false表示不是所有属性都是null
     */
    public static boolean isAllFieldNull(Object object) throws IllegalAccessException {
        boolean flag = true;

        Class<?> clazz = object.getClass();
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            //设置属性是可以访问的(私有的也可以)
            field.setAccessible(true);
            Object value = null;
            value = field.get(object);
            // 只要有1个属性不为空,那么就不是所有的属性值都为空
            if (value != null) {
                flag = false;
                break;
            }
        }
        return flag;
    }


    /**
     * 获取对象getter属性值
     * @param object   对象
     * @param property getter的属性
     * @param <T>      对象类型
     * @param <R>      返回值类型
     * @return 属性值
     */
    public static <T, R> R getPropertyValue(T object, Function<T, R> property) {
        if (object == null) {
            return null;
        }
        return property.apply(object);
    }

    /**
     * 转换方法引用为属性名
     * @param fn  对象获取属性的方法
     * @param <T> 对象类型
     * @return 属性名
     */
    public static <T> String convertToFieldName(SFunction<T> fn) {
        return getSerializedLambda(fn).getImplMethodName();
    }

    /**
     * 获取SerializedLambda对象
     * @param fn lambda方法
     * @return SerializedLambda对象
     */
    private static SerializedLambda getSerializedLambda(Serializable fn) {
        Method method = null;
        SerializedLambda lambda = null;
        try {
            method = fn.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(Boolean.TRUE);
            lambda = (SerializedLambda) method.invoke(fn);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        return lambda;
    }

    @FunctionalInterface
    public interface SFunction<T> extends Serializable {
        Object get(T source);
    }
}
